#include "Preprocessing.h"      //.h文件调用

AdaptiveThreshold::AdaptiveThreshold(struct PreprocessParam &preprocess_param)    //  参数为结构体中preprocess_param的地址，通过地址对结构体进行操作
{
    this->preprocess_param = &preprocess_param;    //对this结构体中的preprocess_param赋值
}

Preprocessing::Preprocessing()   //
{
    element_size = 5;//element的尺寸大小为5，类似于定义五个element
}

Preprocessing::~Preprocessing()
{
    element1 = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(1, 5));//将一个矩形，1*5大小的内核矩阵返回给element1
    element2 = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 7));//将一个3*7的矩形内核矩阵返回给element2
}

void AdaptiveThreshold::adaptiveThresholdProc(cv::Mat src, cv::Mat &dst, int method, int morphology, int iteration, int filter)//定义一个自适应阈值类的函数第一个参数为原图，需要为Mat类8位单通道浮点型图像；第二个参数位输出图像；第三个参数位模式选择；第四个参数位形态学处理方式的选择；第五个参数位迭代的选择；第六个参数位过滤模式的选择
{
    switch (method)//模式选择
    {
    case 0:  // red
    {
        std::vector<cv::Mat> rgbChannels(3);//定义一个三个元素的一维数组，元素类型为Mat类用来储存分离后的颜色通道
        cv::split(src, rgbChannels);//将src图像通道分离结果储存在上面定义的数组中
       // cv::Mat gray = rgbChannels[2] - rgbChannels[0];将蓝色通道的值减去将去红色通道的值的结果赋给gray
        cv::threshold(gray, dst, preprocess_param->gray_thre_min, 255, cv::THRESH_BINARY);//进行阈值操作，gray的像素如果大于 preprocess_param->gray_thre_min（gray的最小值）则变为255 反之则变为0
       
        break;   
    }
    case 1:  // blue
    {
        std::vector<cv::Mat> rgbChannels(3);
        cv::split(src, rgbChannels);
        cv::Mat gray = rgbChannels[0] - rgbChannels[0];
        cv::threshold(gray, dst, preprocess_param->gray_thre_min, 255, cv::THRESH_BINARY);
        break;
    }
    case 2:  // red过曝光
    {
        mulAndIterRedTre(src, dst, preprocess_info_rune);//对于图像中红色通道像素超过曝光值时进行曝光控制
    }
    case 3:  // blue过曝光
    {
        mulAndIterBlueTre(src, dst, preprocess_info_rune);//对于图像中蓝色通道像素超过曝光值时进行曝光控制
    }
    default:
        break;
    }
}

void AdaptiveThreshold::mulAndIterRedTre(cv::Mat src, cv::Mat &bin, PreprocessInfo &preprocess_info)//红过曝光的处理 自适应阈值函数  第一个参数为输入图像第二个参数为输出图像；第三个为 指向bin的Mat类指针；第四个为PreprocessInfo类指向preprocess_info地址的指针
{
    cv::Mat gray_g = cv::Mat::zeros(src.size(), CV_8UC1);//定义一个8位单通道，和原图尺寸大小一致的Mat类矩阵，像素填充为0
    cv::Mat gray_r = cv::Mat::zeros(src.size(), CV_8UC1);//定义一个8位单通道，和原图尺寸大小一致的Mat类矩阵，像素填充为0

    // 因为常量会比变量快，所以当图像通道确定时，所以通道用常量
    int srcRows = src.cols * 3;   //定义一个int型常量，将 src.rows * 3的值赋给它
    for(int i = 0; i < src.rows; i++)   //遍历原来的行
    {
        uchar *p_src = src.data+srcRows * i;   //定义一个指向src.data+srcRows * i行行首的指针
        uchar *p_gray_g = gray_g.data + gray_g.cols * i;//定义一个指向 gray_g.data + gray_g.cols * i行行首的指针
        uchar *p_gray_r = gray_r.data + gray_r.cols * i;//定义一个指向 gray_r.data + gray_r.cols * i行行首的指针
        int jj = 0;
        for(int j = 0; j < srcRows; j += 3)//遍历列
        {
            *(p_gray_g + jj) = *(p_src + j + 1);//将第p_src行列的值赋给第p_gray_g行jj列灰度值
            *(p_gray_r + jj) = *(p_src + j) * 0.1 + *(p_src + j + 1) * 0.2 + *(p_src + j + 2) * 0.7;//将第p_src行j列的值乘以0.1+第p_src第j + 1列的值乘以0.2+第p_src行第j+2列的值乘以0.7的值赋给第p_gray_r第jj列灰度值
            jj++;
        }
    }
    // 最大灰度
    uchar gray_max = gray_r.data[0];//将 gray_r.data中第一个元素设为最大值
    for(int i = 0; i < gray_r.rows; i++)//行变换
    {
        uchar *p = gray_r.data + i * gray_r.cols;//定义一个指针变量,指向 gray_r.data + i * gray_r.cols行的行首
        for(int j = 0; j < gray_r.cols; j++)//列变换
        {
            if(*(p + j) > gray_max)     //将第p行j列的灰度值与最大灰度值进行比较
                gray_max = *(p + j);//若当前灰度值大于最大灰度值则将当前灰度值赋给gray_max
        }
    }//通过遍历像素找出最大灰度

    int &thre = preprocess_info.thre;
    thre = gray_max * preprocess_param->gray_max_w / 10. + avgGrayThreshold(gray_r) * preprocess_param->gray_avg_w / 1.;//计算thre


    VAL_LIMIT(thre, preprocess_param->gray_thre_min, preprocess_param->gray_thre_max);

    cv::threshold(gray_r, bin, thre, 255, 0);//对gtay_r进行阈值操作
}

void AdaptiveThreshold::mulAndIterBlueTre(cv::Mat src, cv::Mat &bin, PreprocessInfo &preprocess_info)
{
    cv::Mat gray_b = cv::Mat::zeros(src.size(), CV_8UC1); //定义一个8位单通道，和原图尺寸大小一致的Mat类矩阵，像素填充为0
    cv::Mat gray_g = cv::Mat::zeros(src.size(), CV_8UC1); //定义一个8位单通道，和原图尺寸大小一致的Mat类矩阵，像素填充为0

    int srcRows = src.cols * 3;//定义一个int数据，将 src.cols * 3的值赋给它
    for(int i = 0; i < src.rows; i++)//遍历原来的行
    {
        uchar *p_src = src.data + srcRows * i;//定义一个指向src.data+srcRows * 行行首的指针
        uchar *p_gray_b = gray_b.data + gray_b.cols * i;///定义一个指向 gray_g.data + gray_g.cols * i行行首的指针
        uchar *p_gray_g = gray_g.data + gray_g.cols * i;//定义一个指向 gray_g.data + gray_g.cols * i行行首的指针

        int jj = 0;
        for(int j = 0; j < srcRows; j += 3)//遍历列
        {
            *(p_gray_b + jj) = *(p_src + j) * 0.7 + *(p_src + j + 1) * 0.2 + *(p_src + j + 2) * 0.1;//将第p_src行j列的值乘以0.7+第p_src第j + 1列的值乘以0.2+第p_src行第j+2列的值乘以0.1的值赋给第p_gray_b第jj列灰度值
            *(p_gray_g + jj) = *(p_src + j + 1);//将第p_src行列的值赋给第p_gray_g行jj列灰度值
            jj++;
        }
    }
    //最大灰度
    uchar gray_max = gray_b.data[0];//将 gray_b.data中第一个元素设为最大值
    for(int i = 0; i < gray_b.rows; i++)//行变换
    {
        uchar *p = gray_b.data + i * gray_b.cols;//定义一个指针变量,指向 gray_r.data + i * gray_b.cols行的行首
        for(int j = 0; j < gray_b.cols; j++)//列变换
        {
            if(*(p + j) > gray_max) //将第p行j列的灰度值与最大灰度值进行比较
                gray_max = *(p + j);//若当前灰度值大于最大灰度值则将当前灰度值赋给gray_max
        }
    }

    int &thre = preprocess_info.thre;
    thre = gray_max * preprocess_param->gray_max_w / 10. + avgGrayThreshold(gray_b) * preprocess_param->gray_avg_w / 1.;//将gray_max的值* preprocess_param结构体中gray_max_w的值除以10+ avgGrayThreshold(gray_b)函数的返回值乘以 preprocess_param结构体中gray_avg_w的值除以1的值赋给thre

    VAL_LIMIT(thre, preprocess_param->gray_thre_min, preprocess_param->gray_thre_max);

    cv::threshold(gray_b, bin, thre, 255, 0); //对gtay_r进行阈值操作
}
}

int AdaptiveThreshold::avgGrayThreshold(cv::Mat src)
{
    long sum_gray = 0;
    for(int j = 0; j < src.rows; j++)  //行变换
    {
        uchar *data = src.ptr<uchar>(j);  //定义一个指向j行行首的指针
        for(int i = 0; i < src.cols; i++)  //列变换
        {
            sum_gray += data[i];      //计算date数组的所有元素之和
        }
    }
    return sum_gray * 1.0 / (src.cols * src.rows);  //date数组的所有元素之总和的值
}

void AdaptiveThreshold::filter(cv::Mat &dst)
{
    //cv::erode(dst, dst, element1);//腐蚀图像
    cv::dilate(dst, dst, element2);//膨胀图像

//    setStructElement();
//    cv::morphologyEx(dst, dst, cv::MORPH_OPEN, element);
//    cv::morphologyEx(dst, dst,cv::MORPH_CLOSE,element);
    cv::medianBlur(dst, dst, 3);//对图像进行滤波，核的大小为3*3
}
